import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' // gltf 模型加载器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

export default class CanvasObject {
  constructor(controls, camera, Mixer = [], actionCamera, actionControls) {
    this.controls = controls;
    this.camera = camera;
    this.Mixer = Mixer; // Mixer 存储所有帧动画的元素
    this.actionCamera = actionCamera;
    this.actionControls = actionControls;
  }
  initThree() {
    const clock = new THREE.Clock(); // 帧动画相关

    /**
     * 将 canvas 绑定到 #three
     */
    const canvas = document.querySelector('#three');
    
    /**
     * Threejs 三要素：scene, render, camera
     * scene 场景
     */
    const scene = new THREE.Scene();
    scene.background = new THREE.Color('#eee'); // 场景的背景颜色
    scene.fog = new THREE.Fog('#eee', 1500, 3500); // 场景的雾
    
    /**
     * renderer 渲染器
     */
    const renderer = new THREE.WebGLRenderer({
      canvas,
      antialias: true // 抗锯齿
    })
    
    /**
     * camera 摄像机
     */
    // PerspectiveCamera (透视摄像机)
    this.camera = new THREE.PerspectiveCamera(
      50, // fov 摄像机视锥体 垂直视野角度
      window.innerWidth / window.innerHeight, // 摄像机视锥体 横纵比
      10, // 近端面
      6000 // 远端面
    )
    
    // 手动调整摄影机位置
    this.camera.position.x = -800;
    this.camera.position.z = 1580;
    this.camera.position.y = 1060;
    
    /**
     *  添加光源
     */
    // 添加个平行光
    const dirLight = new THREE.DirectionalLight(0xffffff, 0.6);
    // 光源等位置
    dirLight.position.set(-10, 8, -5);
    // 可以产生阴影
    dirLight.castShadow = true;
    dirLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
    scene.add(dirLight);
    
    // 添加个半球光
    const hemLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6);
    hemLight.position.set(0, 100, 0);
    scene.add(hemLight);
    
    /**
     * 导入 gltf 模型并为模型创建动画
     */
    var mixer_model; // 帧动画相关
    const gltfLoader = new GLTFLoader();
    gltfLoader.load('./models/scene/scene.gltf', (gltf) => {
      let model = gltf.scene
      scene.position.y = 0; // 让场景中心在人物正中间
      scene.add(model);
     
      mixer_model = new THREE.AnimationMixer(model); // 创建动画混合器（Animation Mixer）, 并取得 AnimationClip 实例列表
      // 遍历所有 gltf 模型里所有的动画
      gltf.animations.forEach(item => {
        mixer_model.clipAction(item).play();
      })
      // mixer.clipAction(gltf.animations[0]).play(); // 只有一个动画效果时
      this.Mixer.push(mixer_model);
    })

    /**
     *  轨道控制器
     */
    this.controls = new OrbitControls(this.camera, renderer.domElement);
    this.controls.enableDamping = true; // 给轨道控制器加上阻尼效果
    this.controls.enableZoom = false; // 默认禁止缩放
    this.controls.autoRotateSpeed = 1.0; // 自动旋转速度
    this.controls.screenSpacePanning = false; // 限制相机平移只能在 xoz 上移动

    /**
     * 调整设备 物理像素分辨率与CSS像素分辨率的比值
     */
    // devicePixelRatio 返回当前显示设备的物理像素分辨率与CSS像素分辨率的比值
    function resizeRendererToDisplaySize(renderer) {
      const canvas = renderer.domElement;
      var width = window.innerWidth;
      var height = window.innerHeight;
      var canvasPixelWidth = canvas.width / window.devicePixelRatio;
      var canvasPixelHeight = canvas.height / window.devicePixelRatio;
    
      const needResize = canvasPixelWidth !== width || canvasPixelHeight !== height
      if (needResize) {
        renderer.setSize(width, height, false)
      }
      return needResize
    }
    
    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement
      this.camera.aspect = canvas.clientWidth / canvas.clientHeight
      this.camera.updateProjectionMatrix()
    }

    /** 
     * ThreeJS 需要一个动画循环函数
     */
    const that = this
    function animate() {
      that.controls.update(); // 刷新轨道控制器
      renderer.render(scene, that.camera); // 刷新渲染器

      // 帧动画相关，在每一帧中更新 mixer 数组里所有元素
      var delta = clock.getDelta();
      that.Mixer.forEach(item => {
        item.update(delta);
      })
      
      // 当窗口横纵比变化时，改变 canvas 比例。
      window.onresize = () => {
        const canvas = renderer.domElement
        that.camera.aspect = canvas.clientWidth / canvas.clientHeight
        that.camera.updateProjectionMatrix()
      }
    
      requestAnimationFrame(animate);
    }
    animate();
  }
  /**
   * 自定义帧动画
   */
  changeCameraPositon() {
    /**
     * 编辑帧动画数据
     */
    let times = [0, 2, 4, 6, 7]; // 关键帧时间数组，离散的时间点序列
    let values = [-800, 1060, 1580, -560, 560, 1180, -120, 360, 200, 60, 400, 180, -800, 1060, 1580]; // 与时间点对应的值组成的数组
    let values2 = [0, 0, 0, -560, 105, 600, 220, 155, 360, 220, 105, -200, 0, 0, 0];
    // 创建位置关键帧对象
    let posTrack = new THREE.KeyframeTrack('this.camera.position', times, values);
    let tarTrack = new THREE.KeyframeTrack('this.controls.target', times, values2);
    
    // duration 决定了默认的播放时间，一般取所有帧动画的最大时间
    let duration = 7;
    let clip = new THREE.AnimationClip("default", duration, [posTrack]);
    let clip2 = new THREE.AnimationClip("default", duration, [tarTrack]);

    /**
     * 播放编辑好的关键帧数据
     */
    let mixer_camera = new THREE.AnimationMixer(this.camera);
    this.actionCamera = mixer_camera.clipAction(clip);

    let mixer_controls = new THREE.AnimationMixer(this.controls);
    this.actionControls = mixer_controls.clipAction(clip2);
    // 通过操作 Action 设置播放方式
    this.actionCamera.loop = THREE.LoopOnce; // 不循环播放
    this.actionCamera.play(); // 开始播放
    this.actionCamera.crossFadeTo(this.actionCamera, 2);

    this.actionControls.loop = THREE.LoopOnce; // 不循环播放
    this.actionControls.play(); // 开始播放
    this.actionControls.crossFadeTo(this.actionControls, 2)

    this.Mixer.push(mixer_camera, mixer_controls);
  }
} 